package com.dream.xcarrecorder;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.media.AudioFormat;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;
import android.util.Log;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat;
import com.dream.libx264.XH264Encoder;
import com.dream.libxrec.encode.audio.ADPCM;
import com.dream.libxrec.player.PCMPlayer;
import com.dream.libxrec.player.audio.G711ADecoder;
import com.dream.libxrec.player.audio.G711UDecoder;
import com.dream.libxrec.utils.G711aUtil;
import com.dream.xcarrecorder.audio.G711Player;
import com.dream.xcarrecorder.rec.CameraHelper;
import com.dream.xcarrecorder.rec.RecHelper;
import com.hhw.libffmpeg.AudioDecoder;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 将录制及相关的业务都和UI解耦，方便后续扩展，如果要看直接的调用，可以看MainActivity类
 */
public class MainActivity2 extends Activity implements View.OnClickListener{
    private Context mContext;
    private ImageView mPicIV;
    private Button mBtnRec,mBtnTakPic,mBtnPreview;
    private LinearLayout mPreviewLayout = null;
    private final RecHelper mRecHelper = RecHelper.getInstance();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        mContext = this;

        initView();
        checkPermission();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            if (!Environment.isExternalStorageManager()){
                Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
                intent.setData(Uri.parse("package:" + getPackageName()));
                startActivityForResult(intent, 1);
            }
        }

//        finish();
    }

    private void checkPermission(){
        boolean isGrantedCamera = ActivityCompat.checkSelfPermission(this,
                Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED;
        boolean isGrantedAudioRecord =  ActivityCompat.checkSelfPermission(this,
                Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED;

        if (isGrantedCamera||isGrantedAudioRecord){
            ActivityCompat.requestPermissions(
                    this,
                    new String[]{Manifest.permission.CAMERA,
                            Manifest.permission.RECORD_AUDIO
                    },0);
        }else{
            RecService.start(mContext);
        }
    }

    private void initView() {
        mPreviewLayout =
                findViewById(R.id.main_btn_rec_preview_layout);
        mPicIV = findViewById(R.id.main_img_pic);
        mPicIV.setOnClickListener(this);
        mBtnRec = findViewById(R.id.main_btn_rec);
        mBtnRec.setOnClickListener(this);
        mBtnRec.setEnabled(true);
        mBtnTakPic = findViewById(R.id.main_btn_takepic);
        mBtnTakPic.setOnClickListener(this);
        mBtnPreview = findViewById(R.id.main_btn_preview);
        mBtnPreview.setOnClickListener(this);
        findViewById(R.id.main_btn_rec_list).setOnClickListener(this);
        findViewById(R.id.main_btn_ffmpeg_test).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        if (id == R.id.main_btn_takepic){
            mRecHelper.takePhoto(0, new CameraHelper.ITakePhotoListener() {
                @Override
                public void onTakePhoto(String channel, Bitmap bitmap) {
                    runOnUiThread(() -> {
                        mPicIV.setImageBitmap(bitmap);
                        mPicIV.setVisibility(View.VISIBLE);
                    });
                }
            });
        }else if (id == R.id.main_btn_rec){
            ctrlRec();//开始录像
        }else if (id == R.id.main_btn_preview) {
            changePreview();
        } else if (id == R.id.main_img_pic){
            mPicIV.setVisibility(View.GONE);
        }else if (id == R.id.main_btn_rec_list){
            RecListActivity.startActivity(this);
        }else if (id == R.id.main_btn_ffmpeg_test){
//            System.out.println(new AudioCodec(1).stringFromJNI());
//            playADPCM();
//            playG726();
//            playG711A();
//            playG711U();
//            playG711A2();
//            playG711U2();
//            playG711A3();
//            playG711A4();
//            playG711U3();
//            testX264();
        }
    }
    FileOutputStream out = null;
    private void testX264() {

        final int WIDTH = 1920;
        final int HEIGHT = 1080;
        final int FRAME_SIZE = WIDTH * HEIGHT * 3 / 2;

        long pts = 0;
        XH264Encoder encoder = new XH264Encoder(WIDTH,HEIGHT);
        String filePath = "/mnt/sdcard/cwt/1738908338941.yuv";
        File file = new File(filePath);
        if (!file.exists()) {
            System.out.println("文件不存在: " + filePath);
            return;
        }

        try {
            out = new FileOutputStream("/mnt/sdcard/cwt/1333.h264");
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (out == null){
            return;
        }

        encoder.setOnEncodedDataAvailableListener(new XH264Encoder.OnEncodedDataAvailableListener() {
            @Override
            public void onFormat(byte[] sps, byte[] pps) {
                try {
                    out.write(sps);
                    out.write(pps);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onEncodedDataAvailable(byte[] encodedData, long pts, boolean isIFrame) {
                try {
                    out.write(encodedData);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });

        try (FileInputStream fis = new FileInputStream(file)) {
            byte[] buffer = new byte[FRAME_SIZE];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                encoder.encodeFrame(buffer,pts+=1);
            }

            encoder.flushAndClose();
            Log.e("TAG","testX264 end");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private void playG711U2() {
        new Thread(new Runnable() {
            @Override
            public void run() {
//                PCMPlayer player = new PCMPlayer(1024,8000,1, AudioFormat.ENCODING_PCM_16BIT);
                G711Player player = new G711Player(G711Player.G711Type.G711_TYPE_U,1024,1);
                File f = new File("/sdcard/test.g711u");
                System.out.println(f.getAbsolutePath()+",size:"+f.length());
                try {
                    FileInputStream inputStream = new FileInputStream(f);

                    byte[] data = new byte[1024];
                    int size = 0;
                    while ((size = inputStream.read(data)) > 0){
                        player.play(data,size);
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void playG711U3() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                PCMPlayer player = new PCMPlayer(1024,8000,1, AudioFormat.ENCODING_PCM_16BIT);
                File f = new File("/sdcard/test.g711u");
                System.out.println(f.getAbsolutePath()+",size:"+f.length());
                try {
                    FileInputStream inputStream = new FileInputStream(f);

                    byte[] data = new byte[1024];
                    short[] pcm = new short[1024];
                    int size = 0;
                    while ((size = inputStream.read(data)) > 0){
                        G711UDecoder.g711u2PCM(data,pcm,0,size);
                        player.play(pcm,size);
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void playG711A3() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                G711Player player = new G711Player(G711Player.G711Type.G711_TYPE_A,1024,1);
                File f = new File("/sdcard/test.alaw");
                System.out.println(f.getAbsolutePath()+",size:"+f.length());
                try {
                    FileInputStream inputStream = new FileInputStream(f);

                    byte[] data = new byte[1024];
                    int size = 0;
                    while ((size = inputStream.read(data)) > 0){
                        player.play(data,size);
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void playG711A4() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                PCMPlayer player = new PCMPlayer(1024,8000,1, AudioFormat.ENCODING_PCM_16BIT);
                File f = new File("/sdcard/test.alaw");
                System.out.println(f.getAbsolutePath()+",size:"+f.length());
                try {
                    FileInputStream inputStream = new FileInputStream(f);

                    byte[] data = new byte[1024];
                    short[] pcm = new short[data.length];
                    int size = 0;
                    while ((size = inputStream.read(data)) > 0){
//                        player.play(data,size);
                        G711ADecoder.g711A2PCM(data,pcm,0,size);
                        player.play(pcm,size);

                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void playG711U() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                PCMPlayer player = new PCMPlayer(1024,8000,1, AudioFormat.ENCODING_PCM_16BIT);

                AudioDecoder codec = new AudioDecoder(AudioDecoder.CODEC_TYPE_G711U);
                codec.create(8000, 1, 64000, new AudioDecoder.IDecodeCallback() {
                    @Override
                    public void onFrame(byte[] data) {
                        player.play(data,data.length);
                    }
                });

                File f = new File("/sdcard/test.g711u");
                System.out.println(f.getAbsolutePath()+",size:"+f.length());
                try {
                    FileInputStream inputStream = new FileInputStream(f);

                    byte[] data = new byte[1024];
                    int size = 0;

                    while ((size = inputStream.read(data)) > 0){
                        codec.decode(data,0,size);
                    }

                    codec.close();

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void playG711A2() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                PCMPlayer player = new PCMPlayer(1024,8000,1, AudioFormat.ENCODING_PCM_16BIT);

                File f = new File("/sdcard/test.alaw");
                System.out.println(f.getAbsolutePath()+",size:"+f.length());
                try {
                    FileInputStream inputStream = new FileInputStream(f);

                    byte[] data = new byte[1024];
                    int size = 0;
                    short[] pcm = new short[data.length];
                    while ((size = inputStream.read(data)) > 0){
                        G711aUtil.G711aDecoder(pcm,data,size);
                        player.play(pcm,pcm.length);

                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }


    private void playG711A() {

        //
        new Thread(new Runnable() {
            @Override
            public void run() {
                PCMPlayer player = new PCMPlayer(1024,8000,1, AudioFormat.ENCODING_PCM_16BIT);

                AudioDecoder codec = new AudioDecoder(AudioDecoder.CODEC_TYPE_G711A);
                codec.create(8000, 1, 64000, new AudioDecoder.IDecodeCallback() {
                    @Override
                    public void onFrame(byte[] data) {
                        player.play(data,data.length);
                    }
                });

                File f = new File("/sdcard/test.alaw");
                System.out.println(f.getAbsolutePath()+",size:"+f.length());
                try {
                    FileInputStream inputStream = new FileInputStream(f);

                    byte[] data = new byte[1024];
                    int size = 0;

                    while ((size = inputStream.read(data)) > 0){
                        codec.decode(data,0,size);
                    }

                    codec.close();

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void playG726(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                PCMPlayer player = new PCMPlayer(1024,8000,1, AudioFormat.ENCODING_PCM_16BIT);

                    AudioDecoder codec = new AudioDecoder(AudioDecoder.CODEC_TYPE_726);
                    codec.create(8000, 1, 32000, new AudioDecoder.IDecodeCallback() {
                        @Override
                        public void onFrame(byte[] data) {
                            player.play(data,data.length);
                        }
                    });

                File f = new File("/sdcard/test.g726");
                System.out.println(f.getAbsolutePath()+",size:"+f.length());
                try {
                    FileInputStream inputStream = new FileInputStream(f);

                    byte[] data = new byte[1024];
                    int size = 0;

                    while ((size = inputStream.read(data)) > 0){
                        codec.decode(data,0,size);
                    }

                    codec.close();

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }

    private void playADPCM() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                PCMPlayer player = new PCMPlayer(1024,8000,1, AudioFormat.ENCODING_PCM_16BIT);

//                    AudioCodec codec = new AudioCodec(AudioCodec.CODEC_TYPE_ADPCM);
//                    codec.create(8000, 1, 32000, new AudioCodec.IDecodeCallback() {
//                        @Override
//                        public void onFrame(byte[] data) {
//                            player.play(data,data.length);
//                        }
//                    });

                File f = new File("/sdcard/test.wav");
                System.out.println(f.getAbsolutePath()+",size:"+f.length());
                try {
                    FileInputStream inputStream = new FileInputStream(f);

                    try {
                        inputStream.read(new byte[86]);
                    }catch (Exception e){
                        e.printStackTrace();
                    }


                    byte[] data = new byte[1024];
                    int size = 0;

                    ADPCM.State state = new ADPCM.State();
                    state.index = 0;
                    state.valprev = 0;

                    while ((size = inputStream.read(data)) > 0){
//                            codec.decode(data,0,size);
                        short[] b = ADPCM.decode(data,size,state);
                        Log.i("adpcm","index:"+state.index+";"+state.valprev);
                        player.play(b,b.length);
                    }
//
//                        codec.close();

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }

    private void changePreview() {

        int size =  mRecHelper.getCameraCount();
        if (mPreviewLayout.getChildCount() == 0){
            mBtnPreview.setText("关闭预览");
            for (int i = 0; i < size; i++) {
                SurfaceView surfaceView = new SurfaceView(mContext);
                LinearLayout.LayoutParams layoutParams =
                        new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT);
                layoutParams.weight = 1;
                surfaceView.setLayoutParams(layoutParams);
                mPreviewLayout.addView(surfaceView);

                mRecHelper.setPreview(i,surfaceView.getHolder().getSurface());

            }
        }else{
            for (int i = 0; i < size; i++) {
                mRecHelper.setPreview(i,null);
            }
            mPreviewLayout.removeAllViews();
            mBtnPreview.setText("开始预览");
        }
    }
    public void ctrlRec() {
        if (mRecHelper.isRun()){
            mBtnRec.setText("开始录像");
            mRecHelper.stop();
        }else{
            try {
                mRecHelper.start();
                mBtnRec.setText("停止录像");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onBackPressed() {
        if (mRecHelper.isRun()){
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setMessage("是否停止录像？");
            builder.setNegativeButton("停止录像",
                    (dialog, which) -> {
                        ctrlRec();
                        dialog.dismiss();
                    });
            builder.setPositiveButton("后台录像",
                    (dialog, which) -> {
                        moveTaskToBack(true);
                        dialog.dismiss();
                    });
            builder.create().show();
        }else{
            super.onBackPressed();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode,String[] permissions,int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        boolean isGrant = true;

        //判断是否每一个权限都同意了。
        for (int res : grantResults) {
            if (res != PackageManager.PERMISSION_GRANTED) {
                isGrant = false;
                break;
            }
        }

        //如果长度为0，则可能为未做任何选择，直接取消了。
        if (grantResults.length > 0 && isGrant) {
            RecService.start(mContext);
        } else {
            //进入APP信息页面
            Uri packageURI = Uri.parse("package:" + getPackageName());
            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI);
            startActivity(intent);
            Toast.makeText(mContext, "不授权权限会导致语音识别无法正常使用！", Toast.LENGTH_SHORT).show();
        }
    }
}
